Function.prototype.myCall = function () {
  if (typeof this !== 'function') {
    throw new Error('call方法只能被函数调用');
  }
  var agrs = [].slice.call(arguments);
  var context = agrs[0] || window;
  context.fn = this;
  var res = eval('context.fn(' + agrs.slice(1) + ')');
  delete context.fn;
  return res;
};

Function.prototype.myApply = function (target, agrs) {
  if (!Array.isArray(args)) {
    throw new Error('agrs 参数必须是一个数组');
  }
  if (typeof this !== 'function') {
    throw new Error('apply方法只能被函数调用');
  }
  var context = target || window;
  context.fn = this;
  var res = eval('context.fn(' + agrs + ')');
  delete context.fn;
  return res;
};

Function.prototype.myBind = function (target) {
  if (typeof this !== 'function') {
    throw new Error('bind方法只能被函数调用');
  }
  var context = target || window;
  var agrs1 = [].slice.call(arguments, 1);
  var _this = this;
  context.fn = _this;
  function Fn() {}
  function callback() {
    /**
     *  1. 正常情况调用，函数内部的this就指向bind调用的第一个参数
     *  2. 如果返回的函数再次使用new来实例化调用，内部会产生一个新的this指向context的原型
     */
    // 被实例化调用
    if (this instanceof Fn && target) {
      context = this;
      context.fn = _this;
    }
    var agrs2 = [].slice.call(arguments, 0);
    var arr = agrs1.concat(agrs2);
    var res = eval('context.fn(' + arr + ')');
    delete context.fn;
    return res;
  }
  Fn.prototype = _this.prototype;
  callback.prototype = new Fn();
  return callback;
};

var name = 'lisi';
function foo(a, b) {
  this.a = a;
  this.b = b;
  console.log(this.name, a, b);
}
var obj = {
  name: 'zhansgan',
};
var newFn = foo.myBind(obj, 1);
newFn(2);
// var f1 = new newFn(1, 2);
// console.dir(f1);

var name = '123';
function Foo(name) {
  this.name = name;
  this.say = function () {
    console.log(this.name);
    setTimeout(function () {
      console.log(this.name);
    }, 1000);
  };
}

var obj = {
  name: '李四',
  say: () => {
    console.log(this.name);
  },
};
var newFn = new (Foo.bind(obj, '张三'))();
newFn.say();
console.dir(newFn);

function waterfall(tasks, callback) {}
